package com.knowledge.plus.java8;

import com.knowledge.plus.java8.pojo.Java8Message;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Map元素映射
 * 将每个元素通过给定的映射函数转换为另一种类型，并返回一个新的Stream
 * <p>
 * {@link Map元素映射#attributeToCollect()}      取集合对象中的某一属性生成为单独的集合（List集合/Set集合）
 * {@link Map元素映射#intListToStrList()}        List<Integer> 转为 List<String>
 * {@link Map元素映射#attributeToMap()}          取集合对象中的两个属性生成为：Map<String, Integer>
 * {@link Map元素映射#collectToMap()}            取集合中的某一属性作为Key 生成为：MapHashMap<key, Object>
 * {@link Map元素映射#object1ToObject2()}        用一对象中的值生成为另一个对象
 *
 * @author TPF
 * @since 2023/2/15
 */
public class Map元素映射 {

    List<CollectStream.Student> list;

    Map元素映射() {
        list = new ArrayList<>();
        list.add(CollectStream.Student.builder().name("张三").age(22).sex("男").build());
        list.add(CollectStream.Student.builder().name("张三").age(66).sex(" ").build());
        list.add(CollectStream.Student.builder().name("李四").age(34).sex(" ").build());
        list.add(CollectStream.Student.builder().name("王五").age(18).sex("女").build());
    }

    /**
     * 取集合对象中的某一属性 作为单独的集合
     */
    @Test
    public void attributeToCollect() {
        // 取一属性，生成为List集合，distinct 去重
        List<String> collectList = list.stream().map(CollectStream.Student::getName).distinct().collect(Collectors.toList());

        // 取一属性，生成为Set集合
        Set<String> collectSet1 = list.stream().map(CollectStream.Student::getName).collect(Collectors.toSet());
        Set<String> collectSet2 = list.stream().map(CollectStream.Student::getName).collect(Collectors.toCollection(TreeSet::new));
    }


    /**
     * Integer 集合转 String 集合
     */
    @Test
    public void intListToStrList() {
        List<String> collectStr = list.parallelStream()
                .map(CollectStream.Student::getAge).collect(Collectors.toSet())
                .parallelStream()
                .map(String::valueOf).collect(Collectors.toList());
    }

    /**
     * 取集合对象中的两个属性生成为：Map<String, Integer>
     */
    @Test
    public void attributeToMap() {
        // key值不唯一，会报错
        Map<String, Integer> map1 = list.stream()
                .collect(Collectors.toMap(CollectStream.Student::getName, CollectStream.Student::getAge));
        System.out.println(map1.keySet() + "  " + map1.values());

        // key值重复，可以这样写。  v.getAge()改成v 则值为对象
        Map<String, Integer> map2 = list.stream()
                .collect(HashMap::new, (k, v) -> k.put(v.getName(), v.getAge()), HashMap::putAll);
        System.out.println(map2.keySet() + "  " + map2.values());

        // key值重复，亦可以这样写
        Map<String, Integer> map3 = list.stream()
                .collect(Collectors.toMap(CollectStream.Student::getName, CollectStream.Student::getAge, (key1, key2) -> key2));
        System.out.println(map3.keySet() + "  " + map3.values());

        // value 为空时
        Map<String, Integer> map4 = list.stream()
                .collect(Collectors.toMap(CollectStream.Student::getName, li -> Objects.isNull(li.getAge()) ? 0 : li.getAge()));
        System.out.println(map4.keySet() + "  " + map4.values());
    }

    /**
     * 取集合中的某一属性作为 Key 生成为：MapHashMap<key, Object>
     */
    @Test
    public void collectToMap() {
        // Key不重复，可以这样写；key值不唯一会报错
        Map<Integer, CollectStream.Student> map1 = list.stream()
                .collect(Collectors.toMap(CollectStream.Student::getAge, Function.identity()));
        System.out.println(map1.keySet() + "  " + map1.values());

        // 转化 Key 值类型（Integer 转化为 String）
        Map<String, CollectStream.Student> strKeyMap = list.stream()
                .collect(Collectors.toMap(student -> student.getAge() + "", Function.identity()));

        // Key值重复，可以这样写
        HashMap<String, CollectStream.Student> map2 = list.stream()
                .collect(HashMap::new, (k, v) -> k.put(v.getName(), v), HashMap::putAll);
        System.out.println(map2.keySet() + "  " + map2.values());

        // Key值重复，亦可以这样写
        Map<String, CollectStream.Student> map3 = list.stream()
                .collect(Collectors.toMap(CollectStream.Student::getName, Function.identity(), (key1, key2) -> key2));
        System.out.println(map3.keySet() + "  " + map3.values());
    }


    /**
     * 将集合中的几个属性取出来，组成一个新对象的集合
     */
    @Test
    public void object1ToObject2() {
        List<Java8Message> java8MessageList = Java8Message.getMessageList();
        List<NewObject> collect = java8MessageList.stream().map(msg -> new NewObject(msg.getId(), msg.getMsg())).collect(Collectors.toList());
        System.out.println(collect);
        /*
         * 较为复杂的写法
         */
        List<NewObject> newCollect = java8MessageList.stream().map(this::messageToNewObject).collect(Collectors.toList());
    }

    public NewObject messageToNewObject(Java8Message java8Message) {
        NewObject obj = new NewObject();
        if (Objects.nonNull(java8Message)) {
            obj.setSid(Optional.ofNullable(java8Message.getId()).orElse(100));
            obj.setRemark(Optional.ofNullable(java8Message.getMsg()).orElse("remark"));
        }
        return obj;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    class NewObject {
        private Integer sid;
        private String remark;
    }

}
